﻿/*
 * OpenDoPE Word Add-In
 * Copyright (C) 2010-2011  Plutext Pty Ltd
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
 * 
 * For details, see http://www.gnu.org/licenses/gpl-2.0.html
 */

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using Office = Microsoft.Office.Core;
using Word = Microsoft.Office.Interop.Word;
using Microsoft.Office.Tools.Word.Extensions; // for VSTOObject

using NLog;

namespace OpenDoPE_Wed
{
    public partial class FormInitialSetup : Form
    {

        static Logger log = LogManager.GetLogger("OpenDoPE_Wed");

        public FormInitialSetup()
        {
            InitializeComponent();
        }

        Office.CustomXMLPart xpathsPart = null;
        Office.CustomXMLPart conditionsPart = null;
        Office.CustomXMLPart questionsPart = null;
        Office.CustomXMLPart componentsPart = null;
        List<Office.CustomXMLPart> cxp = new List<Office.CustomXMLPart>();


        private void buttonOK_Click(object sender, EventArgs e)
        {

            Microsoft.Office.Interop.Word.Document document = null;
            try
            {
                document = Globals.ThisAddIn.Application.ActiveDocument;
            }
            catch (Exception ex)
            {
                Mbox.ShowSimpleMsgBoxError("No document is open/active. Create or open a docx first.");
                return;
            }

            List<Office.CustomXMLPart> cxp = getUserCustomXmlParts();

            if (conditionsPart != null || xpathsPart != null)
            {
                log.Error("Trying to add OpenDoPE parts when already present?!");
                Mbox.ShowSimpleMsgBoxError("ERROR: you can't add OpenDoPE parts when already present?!");
                return;
            }

            if (cxp.Count == 0)
            {
                cxp.Add(addCustomXmlPart(document, "<yourxml>goes here</yourxml>"));
            }
            else
            {
                // Ask user whether they'd like to add another part
                string prompt = "Your docx already contains the following " +  cxp.Count + " Custom XML part(s): " + getCandidatePartsNames(cxp);

                FormInitialSetupUserPart fisup = new FormInitialSetupUserPart(prompt);
                fisup.ShowDialog();

                if (fisup.addUserPart()) {
                    cxp.Add(addCustomXmlPart(document, "<yourxml2>goes here</yourxml2>"));
                }
                fisup.Dispose();
            }

            conditions conditions = new conditions();
            string conditionsXml = conditions.Serialize();
            conditionsPart = addCustomXmlPart(document, conditionsXml);

            components components = new components();
            string componentsXml = components.Serialize();
            componentsPart = addCustomXmlPart(document, componentsXml);

            questionnaire q = null;
            if (this.radioButtonQyes.Checked)
            {
                q = new questionnaire();
            }

            // Add XPath
            xpaths xpaths = new xpaths();

            /* If the document already contains content controls
             * which are bound ("IsMapped"), we need to create
             * entries for them in our XPaths part. */
            string questionID = null;
            int idInt = 1;
            foreach (Word.ContentControl cc in Globals.ThisAddIn.Application.ActiveDocument.ContentControls)
            {
                if (cc.XMLMapping.IsMapped)
                {
                    log.Debug("Adding xpath for " + cc.ID);
                    // then we need to add an XPath
                    string xmXpath = cc.XMLMapping.XPath;

                    if (this.radioButtonQyes.Checked)
                    {
                        // then they need to add a question
                        FormQuestion formQuestion = new FormQuestion(questionsPart, xmXpath);
                        formQuestion.ShowDialog();
                        // TODO - handle cancel

                        question qu = formQuestion.getQuestion();

                        questionID = qu.id;
                        q.questions.Add(qu);

                        formQuestion.Dispose();
                    }

                    xpathsXpath item = new xpathsXpath();
                        // I make no effort here to check whether the xpath
                        // already exists, since the part shouldn't already exist!

                    item.id = "x" +idInt; 

                    if (!string.IsNullOrWhiteSpace(questionID))
                        item.questionID = questionID;

                    xpathsXpathDataBinding db = new xpathsXpathDataBinding();
                    db.xpath = xmXpath;
                    db.storeItemID = cc.XMLMapping.CustomXMLPart.Id;
                    if (!string.IsNullOrWhiteSpace(cc.XMLMapping.PrefixMappings))
                        db.prefixMappings = cc.XMLMapping.PrefixMappings;
                    item.dataBinding = db;

                    xpaths.xpath.Add(item);

                    // Write tag
                    TagData td = new TagData(cc.Tag);
                    td.set("od:xpath", item.id);
                    cc.Tag = td.asQueryString();

                    log.Debug(".. added for " + cc.ID);
                    idInt++;
                }
            }
            string xpathsXml = xpaths.Serialize();
            if (xpathsPart == null)
            {
                xpathsPart = addCustomXmlPart(document, xpathsXml);
            }
            else
            {
                CustomXmlUtilities.replaceXmlDoc(xpathsPart, xpathsXml);
            }


            if (this.radioButtonQyes.Checked)
            {
                string qxml = q.Serialize();
                questionsPart = addCustomXmlPart(document, qxml);
            }

            Microsoft.Office.Tools.Word.Document extendedDocument 
                = Globals.ThisAddIn.Application.ActiveDocument.GetVstoObject(Globals.Factory);
            Microsoft.Office.Tools.CustomTaskPane ctp
                = Globals.ThisAddIn.createCTP(document, cxp, xpathsPart, conditionsPart, questionsPart, componentsPart);
            extendedDocument.Tag = ctp;
            // Want a 2 way association
            WedTaskPane wedTaskPane = (WedTaskPane)ctp.Control;
            wedTaskPane.associatedDocument = document;

            extendedDocument.Shutdown += new EventHandler(
                Globals.ThisAddIn.extendedDocument_Shutdown);

            //taskPane.setupCcEvents(document);

            Mbox.ShowSimpleMsgBoxInfo("Done. Task pane now also open.");

            this.Close();
        }

        /// <summary>
        /// Find OpenDoPE parts; add others to list of custom xml parts.
        /// </summary>
        /// <returns></returns>
        private List<Office.CustomXMLPart> getUserCustomXmlParts()
        {
            List<Office.CustomXMLPart> cxp = new List<Office.CustomXMLPart>();

            foreach (Office.CustomXMLPart cp in Globals.ThisAddIn.Application.ActiveDocument.CustomXMLParts)
            {
                log.Info("cxp: " + cp.DocumentElement + ", " + cp.NamespaceURI
                    + ", " + cp.Id);

                if (cp.NamespaceURI.Equals(Namespaces.XPATHS))
                {
                    xpathsPart = cp;
                }
                else if (cp.NamespaceURI.Equals(Namespaces.CONDITIONS))
                {
                    conditionsPart = cp;
                }
                else if (cp.NamespaceURI.Equals(Namespaces.QUESTIONS))
                {
                    questionsPart = cp;
                }
                else if (cp.NamespaceURI.Equals(Namespaces.COMPONENTS))
                {
                    componentsPart = cp;
                }
                else if (!cp.BuiltIn)
                {
                    cxp.Add(cp);
                }
            }
            return cxp;
        }

        private String getCandidatePartsNames(List<Office.CustomXMLPart> cxp)
        {
            StringBuilder sb = new StringBuilder();

            bool first = true;
            foreach (Office.CustomXMLPart cp in cxp)
            {
                Office.CustomXMLNode node = cp.SelectSingleNode("/node()");
                if (first)
                {
                    sb.Append(node.BaseName);
                    first = false;
                }
                else
                {
                    sb.Append(", " + node.BaseName);
                }
            }

            return sb.ToString();
        }

        private void buttonCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        Office.CustomXMLPart addCustomXmlPart(Word.Document document, string xml)
        {
            object missing = System.Reflection.Missing.Value;

            Office.CustomXMLPart cxp = document.CustomXMLParts.Add(xml, missing);

            log.Debug("part added");

            //bool result = cxp.LoadXML("<mynewpart><blagh/></mynewpart>");
            /* 
            * Can't do this .. causes System.Runtime.InteropServices.COMException
            * "This custom XML part has already been loaded"
            * 
            * Why?  What is the method for if it can't be used?
            * 
            * So our options are:
            * 
            * 1. replace from root node
            * 2. Delete the part, and re-add
            * 
            * Will Word remove the bindings if we do this?
            * 
            */

            //replaceXmlDoc(cxp, "<mynewpart><blagh/></mynewpart>");

            log.Debug("done");

            return cxp;
        }

    }
}
